package com.atguigu.lease.app.service.impl;

import com.atguigu.lease.app.service.LoginService;
import com.atguigu.lease.app.service.UserInfoService;
import com.atguigu.lease.common.consts.RedisConstant;
import com.atguigu.lease.common.consts.StgyAdminConstant;
import com.atguigu.lease.common.util.JwtUtil;
import com.atguigu.lease.common.util.PhoneValidateUtil;
import com.atguigu.lease.common.util.SmsUtil;
import com.atguigu.lease.model.bean.UserInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    UserInfoService userInfoService;
    @Override
    public void getCode(String phone) {
        //1、手机号格式校验
        boolean isMobile = PhoneValidateUtil.isMobile(phone);
        if(!isMobile){
            throw new RuntimeException("手机号格式错误");
        }
        //2、校验手机号获取验证码的频率和次数
        // 2.1 2分钟内不能重复发送： 防止表单重复提交
        //   同一个手机号客户端可能连续发送获取验证码的请求，需要保证连续的相同的请求 2分钟内只有一个可以被处理 其他的拒绝
        // redis. setnx(app:login:limit:1351111111 , "1" , 2 ,分钟) :当键不存在时 才将他设置到redis中
        //              相同的键，第一个请求可以设置成功返回true继续执行，后面的相同键的请求都设置失败返回false不处理！
        Boolean flag = stringRedisTemplate.opsForValue()
                //setnx命令对应的方法
                .setIfAbsent(RedisConstant.APP_LOGIN_LIMIT_PREFIX + phone, "1",
                        2, TimeUnit.MINUTES
                );
        if(!flag){//使用key设置数据失败，key已存在，请求重复提交
            throw new RuntimeException("获取验证码过于频繁");
        }

        // 2.2 一天不能超过5次
        // 在redis中存一个数字 统计获取验证码的手机号 获取的次数，每次获取成功，获取次数+1
        String countStr = stringRedisTemplate.opsForValue()
                .get(RedisConstant.APP_LOGIN_COUNT_PREFIX + phone);
        if(StringUtils.hasText(countStr)){
            //查询到了手机号获取验证码的次数
            int count = Integer.parseInt(countStr);
            if(count>=5){
                //今天获取验证码的次数超过5次
                throw new RuntimeException("获取验证码异常,请联系管理员");
            }

        }


        //3、生成验证码
        String code = RandomStringUtils.randomNumeric(6);
        // 3.1 调用第三方的短信api 给手机号发送短信
//        SmsUtil.sendMsg(phone,code);
        // 3.2 将验证码缓存到redis(登录时还需要使用： 可以使用手机号当做key 来缓存验证码)
        // 验证码有效时间：15分钟
        stringRedisTemplate.opsForValue()
                .set(RedisConstant.APP_LOGIN_CODE_PREFIX + phone, code,
                        15 , TimeUnit.MINUTES);
        //4、成功后 更新 当前手机号的 发送验证码的次数
        //   app:login:count:phone
        // redis：incr基于原来的值+1 ,返回+1后的结果
        Long count = stringRedisTemplate.opsForValue().increment(RedisConstant.APP_LOGIN_COUNT_PREFIX + phone);
        if(count==1){
            //表示手机号今天第一次获取验证码
            stringRedisTemplate.expire(RedisConstant.APP_LOGIN_COUNT_PREFIX+phone,
                    1,TimeUnit.DAYS);
        }
    }

    @Override
    public String login(Map<String, String> loginVo) {
        //1、校验验证码
        String phone = loginVo.get("phone");
        String code = loginVo.get("code");
        //获取redis缓存的验证码
        String cachedCode = stringRedisTemplate.opsForValue().get(RedisConstant.APP_LOGIN_CODE_PREFIX + phone);
        if(!StringUtils.hasText(cachedCode)){
            //如果缓存中没有查到验证码
            throw new RuntimeException("验证码失效");
        }
        if( !cachedCode.equals(code)){
            //  查到的验证码和前端提交的不一致，抛出异常
            throw new RuntimeException("验证码错误");

        }

        //2、根据手机号查询用户信息
        // 移动端会员表 是user_info表
        UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getPhone, phone));
        //2.1 如果用户不存在：注册 将手机号创建为新用户保存
        if(userInfo==null){
            userInfo = new UserInfo();
            userInfo.setPhone(phone);
            userInfo.setNickname("谷粉_"+ UUID.randomUUID().toString().substring(0, 6));
            userInfo.setPassword("000000");
            userInfo.setStatus(1);
            userInfo.setAvatarUrl("https://e-assets.gitee.com/gitee-community-web/_next/static/media/mjc.a8f527c7.png?x-bce-process=image");
            //保存到数据库：
            userInfoService.save(userInfo);
        }
        //2.2 如果用户已存在:直接使用
        //3、根据用户信息创建jwt token

        Map<String, String> params = new HashMap<>();
        params.put(StgyAdminConstant.JWT_TOKEN_USER_ID , userInfo.getId().toString());
        params.put(StgyAdminConstant.JWT_TOKEN_USER_NAME , userInfo.getNickname());
        params.put(StgyAdminConstant.JWT_TOKEN_AVATAR_URL , userInfo.getAvatarUrl());
        return JwtUtil.createToken(params);
    }


}
